package no.rodland.acc.service;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.util.List;
import java.util.Map;

import no.rodland.acc.db.DbRow;
import no.rodland.acc.db.DbUtil;
import no.rodland.acc.db.FetchService;
import no.rodland.acc.db.SqlGenerator;
import no.rodland.acc.model.AccountGroup;
import no.rodland.acc.model.Bank;
import no.rodland.acc.model.BankAccount;
import no.rodland.acc.model.BankType;
import no.rodland.acc.model.Budget;
import no.rodland.acc.model.BudgetAccount;
import no.rodland.acc.model.BudgetAccountGroup;
import no.rodland.acc.model.RowMappers;
import no.rodland.acc.model.TextBudgetAccount;

/**
 * Created by IntelliJ IDEA.
 *
 * @Since: Jun 18, 2010 10:47:53 AM
 * @Author: fmr
 */
class FetchServiceImpl implements FetchService {
    private static final Logger log = Logger.getLogger(FetchServiceImpl.class);

    private final JdbcTemplate template;
    private RowMappers rowMappers;
    private DbServiceImpl cachedService;

    protected FetchServiceImpl(DataSource ds, DbServiceImpl cachedService, RowMappers rowMappers) {
        template = new JdbcTemplate(ds);
        this.rowMappers = rowMappers;
        this.cachedService = cachedService;
    }

    @Override
    public Map<Integer, BankAccount> getBankAccounts() {
        String sql = SqlGenerator.getStar("bank_accounts");
        List<BankAccount> list = template.query(sql, rowMappers.getBankAccountRowMapper());
        return DbUtil.toMap(list);
    }

    @Override
    public Map<Integer, AccountGroup> getAccountGroups() {
        String sql = SqlGenerator.getStar("account_groups");
        List<AccountGroup> list = template.query(sql, rowMappers.getAccountGroupRowMapper());
        return DbUtil.toMap(list);
    }

    @Override
    public Map<Integer, BankType> getBankTypes() {
        String sql = SqlGenerator.getStar("bank_types");

        List<BankType> list = template.query(sql, rowMappers.getBankTypeRowMapper());
        return DbUtil.toMap(list);
    }

    @Override
    public List<Budget> getBudgets(Bank bank) {
        return getBudgets(bank, cachedService.getBudgetAccounts(), cachedService.getBankAccounts());
    }

    List<Budget> getBudgets(Bank bank, final Map<Integer, BudgetAccount> budgetAccounts,
                            final Map<Integer, BankAccount> bankAccounts) {
        String sql = SqlGenerator.getBudgetForBank(bank);
        if (sql == null) {
            return null;
        }
        return template.query(sql, rowMappers.getBudgetRowMapper(budgetAccounts, bankAccounts));
    }

    @Override
    public Bank getNextBank() {
        return getNextBank(cachedService.getBankTypes(), cachedService.getBankAccounts());
    }

    Bank getNextBank(final Map<Integer, BankType> bankTypes,
                     final Map<Integer, BankAccount> bankAccounts) {
        String sql = SqlGenerator.getNextBank();
        List<Bank> list = template.query(sql, rowMappers.getBankRowMapper(bankTypes, bankAccounts));
        if (list.size() == 1) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public Map<Integer, Bank> getBanks() {
        return getBanks(null);
    }

    @Override
    public Map<Integer, Bank> getBanks(final DateTime date) {
        return getBanks(cachedService.getBankTypes(), cachedService.getBankAccounts());
    }

    Map<Integer, Bank> getBanks(final Map<Integer, BankType> bankTypes,
                                final Map<Integer, BankAccount> bankAccounts) {
        return getBanks(bankTypes, bankAccounts, null);
    }

    Map<Integer, Bank> getBanks(final Map<Integer, BankType> bankTypes,
                                final Map<Integer, BankAccount> bankAccounts,
                                final DateTime date) {
        String sql = SqlGenerator.getBank(date);
        List<Bank> list = template.query(sql, rowMappers.getBankRowMapper(bankTypes, bankAccounts));
        return DbUtil.toMap(list);
    }

    @Override
    public Map<Integer, BudgetAccountGroup> getBudgetAccountGroups() {
        return getBudgetAccountGroups(cachedService.getBudgetAccounts(), cachedService.getAccountGroups());
    }

    Map<Integer, BudgetAccountGroup> getBudgetAccountGroups(final Map<Integer, BudgetAccount> budgetAccounts,
                                                            final Map<Integer, AccountGroup> accountGroups) {
        String sql = SqlGenerator.getStar("budget_account_groups");
        List<BudgetAccountGroup> list = template.query(sql,
                rowMappers.getBudgetAccountGroupRowMapper(budgetAccounts, accountGroups));
        return DbUtil.toMap(list);
    }

    @Override
    public Map<Integer, BudgetAccount> getBudgetAccounts() {
        return getBudgetAccounts(cachedService.getAccountGroups());
    }

    public Map<Integer, BudgetAccount> getBudgetAccounts(final Map<Integer, AccountGroup> accountGroups) {
        String sql = SqlGenerator.getStar("budget_accounts");
        List<BudgetAccount> list = template.query(sql, rowMappers.getBudgetAccountRowMapper(accountGroups));
        return DbUtil.toMap(list);
    }

    @Override
    public Map<Integer, TextBudgetAccount> getTextBudgetAccounts() {
        return getTextBudgetAccounts(cachedService.getBudgetAccounts());
    }

    Map<Integer, TextBudgetAccount> getTextBudgetAccounts(final Map<Integer, BudgetAccount> budgetAccounts) {
        String sql = SqlGenerator.getStar("text_budget_accounts");
        List<TextBudgetAccount> list = template.query(sql, TextBudgetAccount.getRowMapper(budgetAccounts));
        return DbUtil.toMap(list);
    }

    @Override
    public <T extends DbRow> T getRowById(DbRow row, int id, RowMapper<T> rowMapper) {
        final String tableName = row.getTableName();
        String sql = SqlGenerator.getById(id, tableName);
        return template.query(sql, rowMapper).get(0);
    }
}
